package cn.dt.ymcc.service.impl;

import cn.dt.ymcc.domain.KillActivity;
import cn.dt.ymcc.domain.KillCourse;
import cn.dt.ymcc.mapper.KillActivityMapper;
import cn.dt.ymcc.service.IKillActivityService;
import cn.dt.ymcc.service.IKillCourseService;
import cn.dt.ymcc.util.AssertUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author whale.dai
 * @since 2022-08-05
 */
@Service
public class KillActivityServiceImpl extends ServiceImpl<KillActivityMapper, KillActivity> implements IKillActivityService {
    @Autowired
    private IKillCourseService killCourseService;
    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    /**
     * 发布秒杀活动
     * 判断课程开始时间是否是在秒杀活动结束之后（不是报错）
     * 1.修改t_kill_activity的publish_status发布状态为上架1，上架时间
     * 将所有秒杀课程存redis，使用hash，设置大小key
     * 2通过activityId获取对应t_kill_course的所有对象并存入redis中，设置信号量
     * @param activityId
     */
    @Override
    public void eventOnline(Long activityId) {
        Date now = new Date();
        //获取活动对象
        KillActivity killActivity = selectById(activityId);
        List<KillCourse> killCourses = getKillCoursesByactId(activityId);
        Date startTime = killCourses.get(0).getStartTime();//此处可以通过遍历查看开始时间，但是这样效率就很低
        //判断课程开始时间是否是在秒杀活动结束之前（不是报错）
        AssertUtil.isTrue(startTime.before(killActivity.getEndTime()),"课程活动开始时间有误");
        for (KillCourse killCoure : killCourses) {
            String key = activityId+":"+killCoure.getId();//这是用来获取redis中value的key
            //2.设置信号量,通过activityId获取对应t_kill_course的所有对象并存入redis中，
            //获取每一个课程对应的信号量
            RSemaphore semaphore = redissonClient.getSemaphore(key);
            //设置秒杀数量
            boolean setPermits = semaphore.trySetPermits(killCoure.getKillCount());
            //设置成功就存redis，失败了就发消息给运维处理
            if(setPermits){
                //设置的大Key为activity: 7(活动id)，小Key为15(课程id)
                redisTemplate.opsForHash().put("activity:"+activityId,killCoure.getId().toString(),killCoure);
                //1.修改t_kill_activity的publish_status发布状态为上架1，上架时间
                killActivity.setPublishStatus(1);
                killActivity.setPublishTime(now);
                killCoure.setPublishStatus(1);
                killCoure.setPublishTime(now);
                updateById(killActivity);

            }else{
                //失败了就发消息给运维处理
                //@TODO

            }


        }


    }

    /**
     *秒杀活动下架
     * 1.将活动的状态改为结束
     * 2.删除redis中存的该活动所有课程数据
     * @param activityId
     */
    @Override
    public void eventOffline(Long activityId) {
        KillActivity killActivity = selectById(activityId);
        //1.将活动的状态改为结束
        killActivity.setPublishStatus(KillActivity.PUBLISH_STATUS_CANCEL);
        //2.删除redis中存的该活动所有课程数据
        redisTemplate.delete("activity:"+activityId);
        Set<Object> keys = redisTemplate.keys(activityId + ":*");
        redisTemplate.delete(keys);


    }

    /**
     * 通过activityId获取killcourses
     * @param activityId
     * @return
     */
    private List<KillCourse> getKillCoursesByactId(Long activityId) {
        Wrapper<KillCourse> wrapper = new EntityWrapper<>();
        wrapper.eq("activity_id", activityId);
        return killCourseService.selectList(wrapper);
    }
}
